﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Semantics;
using Semantics.IR;
using Semantics.Base;

namespace AutoResponse.Dialogue
{
    class DialogueProcessor
    {
        public Memory Memory = new Memory();
        private Node currentNode;
        private Edge currentAnticipation;

        public DialogueProcessor()
        {
        }
         public string Hello()
        {
            //currentAnticipation = Memory.ResolveNode("[人]");
            return this.robot("你好！我叫罗伯特，请问你的姓名是？");
        }
        public string robot(string str)
        {
            return "罗伯特说：\n  " + str + "\n";
        }


        //public void CreateNewNode(string str, string str2)
        //{
        //    Edge edge;
        //    Node node;
        //    switch (str)
        //    {
        //        case "姓名":
        //            break;
        //        case "年龄":
        //            node = new Node(str2);
        //            memory.EnrollNode(node);
        //            edge = new Edge(nameNode, currentNode, node);
        //            memory.EnrollEdge(edge);
        //            break;
        //        case "性别":
        //            node = new Node(str2);
        //            memory.EnrollNode(node);
        //            edge = new Edge(nameNode, currentNode, node);
        //            memory.EnrollEdge(edge);
        //            break;
        //        case "学校":
        //            node = new Node(str2);
        //            memory.EnrollNode(node);
        //            edge = new Edge(nameNode, currentNode, node);
        //            memory.EnrollEdge(edge);
        //            break;
        //    }
        //}
        
        public string GenerateResponse(Node topicnode)
        {
            Edge templateproperty = SearchMissingSlot(topicnode, topicnode.Parent);
            if (templateproperty!=null)
            {
                currentAnticipation = templateproperty;
                return this.robot(this.currentNode.Value + "->" + currentAnticipation.Class.Value + "->?");
            }
            else
                return this.robot("你怎么样？");
        }
        enum PragmaticType
        {
            Phrase,
            Narration,
            Question,
            Acknolwedgement
        }
        PragmaticType GetPragmaticType(Graph graph)
        {
            if (graph.edgesHash.Count == 0)
                return PragmaticType.Phrase;
            else
                return PragmaticType.Narration;
        }

        void SetupCorrespondent(Graph response)
        {
            this.Memory.Merge(response);
            switch (GetPragmaticType(response))
            {
                case PragmaticType.Phrase:
                    {
                        this.currentNode = new Node("[对方]");
                        this.Memory.EnrollNode(this.currentNode);
                        Node namenode = new Node(response.RootNode.Value);// Semantics.IR.GraphUtility.ResolveOrCreate(this.Memory, response.RootNode);
                        this.Memory.EnrollNode(namenode);
                        Edge nameproperty = Edge.ConnectNode(this.currentNode, this.Memory.ResolveNode("姓名"), namenode);
                        this.Memory.EnrollEdge(nameproperty);
                        Node human = this.Memory.ResolveNode("[人]");
                        Edge iskind = Edge.ConnectNode(this.currentNode, this.Memory.IsKindOfNode, human);
                        this.Memory.EnrollEdge(iskind);
                        break;
                    }
                case PragmaticType.Narration:
                    {
                        if (response.RootNode.Class.Is("Aa"))
                        {
                            this.ResolveCoreference(response, response.RootNode);
                        }
                        this.Memory.Merge(response);
                        this.currentNode = this.Memory.ResolveNode(response.RootNode.Value);
                        Node human = this.Memory.ResolveNode("[人]");
                        if (!this.currentNode.Is(human))
                        {//避免重复创建IsKindOf连接
                            Edge iskind = Edge.ConnectNode(this.currentNode, this.Memory.IsKindOfNode, human);
                            this.Memory.EnrollEdge(iskind);
                        }
                        break;
                    }
                default:
                    throw new NotImplementedException();
            }
        }

        /// <summary>
        /// 指代解析
        /// </summary>
        /// <param name="graph"></param>
        /// <param name="correfenrence"></param>
        void ResolveCoreference(Graph graph, Node correfenrence)
        {
            string[,] correferencemap=
            {
                {"我","[对方]"},
            };

            for(int i=0;i<correferencemap.GetLength(0);i++)
            {
                if(correferencemap[i,0]==correfenrence.Value)
                {
                    correfenrence.Value=correferencemap[i,1];
                }
            }

        }

        Edge SearchMissingSlot(Node instance, Node catetory)
        {

            IList<List<Edge>> properties = catetory.TypedOutEdgeLists.Values;
            for (int i = 0; i < properties.Count; i++)
            {
                List<Edge> property = properties[i];
                System.Diagnostics.Debug.Assert(properties.Count > 0);
                Node propertytype=property[0].Class;
                if (propertytype == Memory.IsKindOfNode)
                    continue;
                List<Edge> maybeexist = instance.GetEdges(propertytype, Edge.EdgeDirection.Out, false);
                Node existpropertyvalue = instance[propertytype];
                if (existpropertyvalue != null)
                    continue;
                return property[0];
            }
            return null;
        }

        public ProcessResult Response(string input)
        {
            ProcessResult result = new ProcessResult();
            result.Words = input;
            if (!Preparser.PreParse(result))
                this.Parse(result);
            Transformer transformer = new Transformer((Graph)NLP.Dictionary);
            transformer.Transform(result.Graph);
            this.ProcessInputGraph(result.Graph);
            result.Response = this.GenerateResponse(this.currentNode);
            return result;
        }

        Node NewWord;
        void Parse(ProcessResult result)
        {
            string name = SearchName(result.Words);

            string text = null;
            if (name != null)
            {
                Node[] exist = NLP.Dictionary.GetWord(name, "[事物]");
                if (exist == null)
                {
                    NLP.Dictionary.InsertWord(name, "[事物]");
                    NewWord = NLP.Dictionary.GetWord(name, "[事物]")[0];
                }
                text = Clean(name, result.Words);
            }
            else
                text = result.Words;
            ISemanticParser semanticparser = (ISemanticParser)NLP.CreateSemanticParser();
            result.ParseResults = semanticparser.SemanticParse(text);

            if (result.ParseResults.Count == 1)
            {
                ISemantizer semantizer = new Semantics.IR.Semantizer(KnowledgeBase.Reference.KnowledgeSet);
                result.Graph = semantizer.Semantize(result.ParseResults[0]);
                result.Result = result.ParseResults[0];
            }
            else
            {
                ResolveAmbiguities(result);
            }
        }
        void ResolveAmbiguities(ProcessResult result)
        {
            List<Graph> candidates = new List<Graph>();
            for (int i = 0; i < result.ParseResults.Count; i++)
            {
                ISemantizer semantizer = new Semantics.IR.Semantizer(KnowledgeBase.Reference.KnowledgeSet);
                Graph meaning = semantizer.Semantize(result.ParseResults[i]);
                if (meaning.RootNode.Class.Is(this.currentAnticipation.Incoming.Class))
                {
                    candidates.Add(meaning);
                    result.Result = result.ParseResults[i];
                }
            }
            if (candidates.Count == 1)
            {
                result.Graph = candidates[0];
                
            }
            else if(candidates.Count==0)
            {
                throw new Exception("没有期待的词义");
            }
            else
            {
                string text="歧义的词语:\r\n";
                for(int i=0;i<candidates.Count;i++)
                {
                    text+=candidates[i].RootNode.Class.ToString("H")+"\r\n";
                }
                throw new Exception(text);
            }
        }
        void ProcessInputGraph(Graph graph)
        {
            if (this.currentNode == null)
                SetupCorrespondent(graph);
            else
            {
                Node rootnode = Merge(graph);
                switch (GetPragmaticType(graph))
                {
                    case PragmaticType.Phrase:
                        {
                            Edge existedge = rootnode.GetEdge(Memory.IsKindOfNode, Edge.EdgeDirection.Out, currentAnticipation.Incoming);
                            if (existedge == null)
                            {
                                Edge edge = Edge.ConnectNode(rootnode, Memory.IsKindOfNode, currentAnticipation.Incoming);
                                Memory.EnrollEdge(edge);
                            }
                            this.FillSlot(rootnode);
                            break;
                        }
                }
            }
        }


        public Node Merge(Graph graph)
        {
            Memory.Merge(graph);
            Node root = Memory.ResolveNode(graph.RootNode.Value);
            return root;
        }

        //string OnWord(string input)
        //{
        //    switch (currentAnticipation.Value)
        //    {
        //        case "姓名":
        //            return  OnNewContact(input);
        //        default:
        //            {
        //                FillSlot(input);
        //                return GenerateResponse(this.currentNode);
        //            }
        //    }
        //}


        public string SearchName(string str)
        {
            string[] splitName;
            string name;
            splitName = str.Split('<');
            if (splitName.Length == 1)
                return null;
            splitName = splitName[1].Split('>');
            name = splitName[0];
            return name;
        }

        public string Clean(string name, string str)
        {
            string cleanStr;
            cleanStr = str.Replace("<", "");
            cleanStr = cleanStr.Replace(">", "");
            return cleanStr;
        }

        void FillSlot(Node valuenode)
        {
            Edge exist = currentNode.GetEdge(currentAnticipation.Class, Edge.EdgeDirection.Out, valuenode);
            if (exist == null)
            {
                Edge edge = Edge.ConnectNode(currentNode, currentAnticipation.Class, valuenode);
                Memory.EnrollEdge(edge);
            }
        }

        //public string OnNewContact(string name)
        //{
        //    this.currentNode = new Node(name);
        //    //this.Memory.EnrollNode(this.currentNode);
        //    Node human = Memory.ResolveNode("人");

        //    Edge edge = Edge.ConnectNode(currentNode, Memory.IsKindOfNode, human);
        //    Memory.EnrollEdge(edge);

        //    Node nameNode = new Node(name);
        //    Memory.EnrollNode(nameNode);
        //    edge = Edge.ConnectNode(this.currentNode, currentAnticipation, nameNode);
        //    Memory.EnrollEdge(edge);

        //    return GenerateResponse(currentNode);

        //}
    }
}
